/*
 * Copyright (C) <2009> <fscops> <Rishi B Agrawal> (postrishi@gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version->
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE->  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/highmem.h>

#define MAX_EXTENTION_LENGTH 5 
#define ohsm_debug  /* Enable printks */

/*
 * Data structure used for allocation policy.
 */

struct ohsm_uid_tier {
	uid_t uid;					/* user id */
	unsigned char tier;				/* respective tier of the user */
};

struct ohsm_gid_tier {
	gid_t gid;		 			/* group id*/
	unsigned char tier;				/* respective tier of the group */
};

struct ohsm_type_tier {
	char type[MAX_EXTENTION_LENGTH];		/* file extention */
	unsigned  char tier;				/* respective tier for the file type */
};

struct ohsm_allocation_policy {
	struct ohsm_uid_tier uid_tier[100];			/* address of dyamically created ohsm_uid_tier */ 
	struct ohsm_gid_tier gid_tier[100];			/* address of dynamically created ohsm_gid_tier */
	struct ohsm_type_tier type_tier[100];		/* address of dynamically created ohsm_type_tier*/
	int uidx; // Remove th indexes ???
	int gidx;
	int tidx;
	int cnt_users;					/* count of users for which tier has been specified*/
	int cnt_groups;					/* count of groups for which tier has been specified*/
	int cnt_types;					/* count of file types for which tier has been specified*/
};

extern struct ohsm_allocation_policy *allocpol;

/* OHSM allocation test */

/************************************************************	
 *
 * get_tier_name2 () compares the type of created file 
 * with the given allocation policy file
 *
 * returns the tier-id specified in the allocation policy
 * file else zero for default allocation
 *
 ***********************************************************/
 
unsigned char get_tier_name2 (char *namex) {
	unsigned char i;
	#ifdef ohsm_debug
		printk (KERN_ALERT "In get Tier name 2");
		printk (KERN_ALERT "\nThe EXTENSION entered is %s\n", namex);
		printk (KERN_ALERT "\nThe Policy Tables -> type (number of types) %u\n",
		allocpol->cnt_types);
	#endif
	for (i = 0; i < allocpol->cnt_types; i++) {
		#ifdef ohsm_debug	
			printk (KERN_ALERT "\nThe Value of i outside loop is %u\n", i);
		#endif
		if (!strcmp (namex, allocpol->type_tier[i].type)) {
			#ifdef ohsm_debug
				printk (KERN_ALERT "\nThe Value of i is %u\n", i);
			#endif
		        return allocpol->type_tier[i].tier;
		}
	}
	return 0;
}

/************************************************************	
 *
 * get_tier_name () extracts the extension out of the 
 * name and call get_tier_name2
 *
 * returns the tier-id specified in the allocation policy
 * file else zero for default allocation
 *
 ***********************************************************/
 
unsigned char get_tier_name (char *nam, unsigned int len) {
	unsigned int i;
	unsigned char temp;
	
	if( allocpol->cnt_types == 0){
		return 0;
	}
	#ifdef ohsm_debug
		printk (KERN_ALERT "\nIn get_tier_name\n");
		printk (KERN_ALERT "\nThe Name Entered %s\n", nam);
		printk (KERN_ALERT "\nThe Lenth is %u\n", len);
	#endif
	for (i = len - 1; i >= 0; i--) {
		if (*(nam + i) == '.') {
			#ifdef ohsm_debug
				printk (KERN_ALERT "\nThe Current character %c Name : %s Name : %s", *(nam + i), nam, nam);
			#endif
			temp = get_tier_name2 ((char *) (nam + i + 1));
			return temp;
		}
	}
	return 0;
}

/************************************************************	
 *
 * get_tier_uid () compares the current uid with the
 * given uid in allocation policy file
 *
 * returns the tier-id specified in the allocation policy
 * file else zero for default allocation
 *
 ***********************************************************/
 
unsigned char get_tier_uid (uid_t uidx) {
	unsigned int i;
	#ifdef ohsm_debug
		printk (KERN_ALERT "\nIn get uid tier");
	#endif
	if( allocpol->cnt_users == 0){
		return 0;
	} 
	for (i = 0; i < allocpol->cnt_users; i++) {
		#ifdef ohsm_debug
			printk (KERN_ALERT "\nInside Loop of UID");
		#endif
		if (uidx == allocpol->uid_tier[i].uid) {
			return allocpol->uid_tier[i].tier;
		}
	}
	return 0;
}

/************************************************************	
 *
 * get_tier_gid () compares the current gid with the
 * given gid in allocation policy file
 *
 * returns the tier-id specified in the allocation policy
 * file else zero for default allocation
 *
 ***********************************************************/
 
unsigned char get_tier_gid (gid_t gidx) {
  	unsigned int i;
	#ifdef ohsm_debug
		printk (KERN_ALERT "\nIn get Gid tier");
	#endif
	if ( allocpol->cnt_groups == 0){
		return 0;
	}
	for (i = 0; i < allocpol->cnt_groups; i++) {
		#ifdef ohsm_debug
			printk (KERN_ALERT "\nInside the loop of GID");
		#endif
		if (gidx == allocpol->gid_tier[i].gid) {
			return allocpol->gid_tier[i].tier;
		}
	}
	return 0;
}

/************************************************************	
 *
 * ohsm_get_tier () provides the tier id for the allocation
 * file.
 *
 * returns the tier-id specified in the allocation policy
 * file else zero for default allocation.
 * (first according to type then uid then gid)
 *
 ***********************************************************/

unsigned char ohsm_get_tier(struct dentry *dentry) {
	char nam[256];
	unsigned char retval;

	strncpy (nam, dentry->d_name.name,dentry->d_name.len);
	retval = get_tier_name (nam, dentry->d_name.len);
	if( retval){
		return retval;
	}
	#ifdef ohsm_debug
		printk (KERN_ALERT "\nCalling Get Tier Uid\n");
	#endif
	retval = get_tier_uid (current->real_cred->uid);
	if( retval){
		return retval;
	}
	#ifdef ohsm_debug
		printk (KERN_ALERT "\nCalling Get Tier Gid\n");
	#endif
	retval = get_tier_gid (current->real_cred->gid);
	if( retval){
		return retval;
	}
	return 0; 
}
